home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / Keyboard / keyboard.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  24.5 KB  |  646 lines

  1. //-----------------------------------------------------------------------------
  2. // File: keyboard.cpp
  3. //
  4. // Desc: The Keyboard sample show how to use a DirectInput keyboard device 
  5. //       and the differences between cooperative levels and data styles. 
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #define DIRECTINPUT_VERSION 0x0800
  11.  
  12. #include <tchar.h>
  13. #include <windows.h>
  14. #include <commctrl.h>
  15. #include <basetsd.h>
  16. #include <dinput.h>
  17. #include "resource.h"
  18.  
  19.  
  20. //-----------------------------------------------------------------------------
  21. // Function-prototypes
  22. //-----------------------------------------------------------------------------
  23. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  24. HRESULT OnInitDialog( HWND hDlg );
  25. VOID    UpdateUI( HWND hDlg );
  26. HRESULT OnCreateDevice( HWND hDlg );
  27. HRESULT ReadImmediateData( HWND hDlg );
  28. HRESULT ReadBufferedData( HWND hDlg );
  29. VOID    FreeDirectInput();
  30.  
  31.  
  32.  
  33.  
  34. //-----------------------------------------------------------------------------
  35. // Defines, constants, and global variables
  36. //-----------------------------------------------------------------------------
  37. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  38. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  39.  
  40. #define SAMPLE_BUFFER_SIZE 8  // arbitrary number of buffer elements
  41.  
  42. LPDIRECTINPUT8       g_pDI       = NULL; // The DirectInput object         
  43. LPDIRECTINPUTDEVICE8 g_pKeyboard = NULL; // The keyboard device 
  44.  
  45.  
  46. //-----------------------------------------------------------------------------
  47. // Name: WinMain()
  48. // Desc: Entry point for the application.  Since we use a simple dialog for 
  49. //       user interaction we don't need to pump messages.
  50. //-----------------------------------------------------------------------------
  51. int WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int )
  52. {
  53.     InitCommonControls();
  54.  
  55.     // Display the main dialog box.
  56.     HWND hDlg = CreateDialog( hInst, MAKEINTRESOURCE(IDD_KEYBOARD), NULL, MainDlgProc );
  57.  
  58.     // Background message loop
  59.     MSG msg;
  60.     while( GetMessage( &msg, NULL, 0, 0) )
  61.     {
  62.         if( g_pKeyboard )
  63.         {
  64.             // If the keyboard is acquired in non-exclusive mode, windows will 
  65.             // continue to send key messages to the application. In dialog boxes, 
  66.             // these messages interact with the dailog's controls if handled, and 
  67.             // trigger the default beep sound if unhandled. This code filters
  68.             // out undesired key messages if the keyboard is currently acquired.
  69.             if( msg.message == WM_KEYDOWN )
  70.             {
  71.                 switch( msg.wParam )
  72.                 {
  73.                     case VK_ESCAPE:
  74.                     case VK_F1:
  75.                         // Let the dialog see these keys
  76.                         break;
  77.  
  78.                     default:
  79.                         // Block all other keyboard message
  80.                         continue;
  81.                 }
  82.             }
  83.         }
  84.        
  85.         // Forward the message to the dialog
  86.         IsDialogMessage( hDlg, &msg );
  87.     }
  88.     
  89.     return TRUE;
  90. }
  91.  
  92.  
  93.  
  94.  
  95.  
  96. //-----------------------------------------------------------------------------
  97. // Name: MainDlgProc()
  98. // Desc: Handles dialog messages
  99. //-----------------------------------------------------------------------------
  100. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  101. {
  102.     switch( msg ) 
  103.     {
  104.         case WM_INITDIALOG:
  105.             OnInitDialog( hDlg );
  106.             break;
  107.         
  108.         case WM_COMMAND:
  109.             switch( LOWORD(wParam) )
  110.             {
  111.                 case IDCANCEL:
  112.                     EndDialog( hDlg, 0 );
  113.                     PostQuitMessage( 0 ); 
  114.                     break;
  115.  
  116.                 case IDC_EXCLUSIVE:
  117.                 case IDC_NONEXCLUSIVE:
  118.                 case IDC_FOREGROUND:
  119.                 case IDC_BACKGROUND:
  120.                 case IDC_IMMEDIATE:
  121.                 case IDC_BUFFERED:
  122.                 case IDC_WINDOWSKEY:
  123.                     UpdateUI( hDlg );
  124.                     break;
  125.  
  126.                 case IDC_CREATEDEVICE:
  127.                     if( NULL == g_pKeyboard )
  128.                     {
  129.                         if( FAILED( OnCreateDevice( hDlg ) ) )
  130.                         {
  131.                             MessageBox( hDlg, _T("CreateDevice() failed. ")
  132.                                               _T("The sample will now exit."), 
  133.                                               _T("Keyboard"), MB_ICONERROR | MB_OK );
  134.                             FreeDirectInput();
  135.                         }
  136.                     }
  137.                     else
  138.                     {
  139.                         FreeDirectInput();
  140.                     }
  141.  
  142.                     UpdateUI( hDlg );
  143.                     break;
  144.  
  145.                 default:
  146.                     return FALSE; // Message not handled 
  147.             }       
  148.             break;
  149.  
  150.         case WM_ACTIVATE:
  151.             if( WA_INACTIVE != wParam && g_pKeyboard )
  152.             {
  153.                 // Make sure the device is acquired, if we are gaining focus.
  154.                 g_pKeyboard->Acquire();
  155.             }
  156.             break;
  157.         
  158.         case WM_TIMER:
  159.             // Update the input device every timer message
  160.             {
  161.                 BOOL bImmediate = ( IsDlgButtonChecked( hDlg, IDC_IMMEDIATE  ) == BST_CHECKED );
  162.  
  163.                 if( bImmediate )
  164.                 {
  165.                     if( FAILED( ReadImmediateData( hDlg ) ) )
  166.                     {
  167.                         KillTimer( hDlg, 0 );    
  168.                         MessageBox( NULL, _T("Error reading input state. ")
  169.                                           _T("The sample will now exit."), 
  170.                                           _T("Keyboard"), MB_ICONERROR | MB_OK );
  171.                         EndDialog( hDlg, TRUE ); 
  172.                     }
  173.                 }
  174.                 else
  175.                 {
  176.                     if( FAILED( ReadBufferedData( hDlg ) ) )
  177.                     {
  178.                         KillTimer( hDlg, 0 );    
  179.                         MessageBox( NULL, _T("Error reading input state. ")
  180.                                           _T("The sample will now exit."), 
  181.                                           _T("Keyboard"), MB_ICONERROR | MB_OK );
  182.                         EndDialog( hDlg, TRUE ); 
  183.                     }
  184.                 }
  185.             }
  186.             break;
  187.         
  188.         case WM_DESTROY:
  189.             // Cleanup everything
  190.             KillTimer( hDlg, 0 );    
  191.             FreeDirectInput();    
  192.             break;
  193.  
  194.         default:
  195.             return FALSE; // Message not handled 
  196.     }
  197.  
  198.     return TRUE; // Message handled 
  199. }
  200.  
  201.  
  202.  
  203.  
  204. //-----------------------------------------------------------------------------
  205. // Name: OnInitDialog()
  206. // Desc: Initialize the DirectInput variables.
  207. //-----------------------------------------------------------------------------
  208. HRESULT OnInitDialog( HWND hDlg )
  209. {
  210.     // Load the icon
  211.     HICON hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE( IDI_MAIN ) );
  212.  
  213.     // Set the icon for this dialog.
  214.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  215.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  216.  
  217.     // Check the 'exclusive', 'foreground', and 'immediate' buttons by default. 
  218.     CheckRadioButton( hDlg, IDC_EXCLUSIVE,  IDC_NONEXCLUSIVE, IDC_EXCLUSIVE );
  219.     CheckRadioButton( hDlg, IDC_FOREGROUND, IDC_BACKGROUND,   IDC_FOREGROUND );
  220.     CheckRadioButton( hDlg, IDC_IMMEDIATE,  IDC_BUFFERED,     IDC_IMMEDIATE );
  221.  
  222.     UpdateUI( hDlg );
  223.  
  224.     return S_OK;
  225. }
  226.  
  227.  
  228.  
  229.  
  230. //-----------------------------------------------------------------------------
  231. // Name: UpdateUI()
  232. // Desc: Enables/disables the UI, and sets the dialog behavior text based on the UI
  233. //-----------------------------------------------------------------------------
  234. VOID UpdateUI( HWND hDlg )
  235. {
  236.     TCHAR   strExcepted[2048];
  237.     BOOL    bExclusive;
  238.     BOOL    bForeground;
  239.     BOOL    bImmediate;
  240.     BOOL    bDisableWindowsKey;
  241.  
  242.     // Detrimine where the buffer would like to be allocated 
  243.     bExclusive         = ( IsDlgButtonChecked( hDlg, IDC_EXCLUSIVE  ) == BST_CHECKED );
  244.     bForeground        = ( IsDlgButtonChecked( hDlg, IDC_FOREGROUND ) == BST_CHECKED );
  245.     bImmediate         = ( IsDlgButtonChecked( hDlg, IDC_IMMEDIATE  ) == BST_CHECKED );
  246.     bDisableWindowsKey = ( IsDlgButtonChecked( hDlg, IDC_WINDOWSKEY ) == BST_CHECKED );
  247.  
  248.     if( g_pKeyboard )
  249.     {
  250.         SetDlgItemText( hDlg, IDC_CREATEDEVICE, TEXT("Release Device") );
  251.         SetDlgItemText( hDlg, IDC_DATA, TEXT("") );
  252.  
  253.         EnableWindow( GetDlgItem( hDlg, IDC_EXCLUSIVE    ), FALSE );
  254.         EnableWindow( GetDlgItem( hDlg, IDC_NONEXCLUSIVE ), FALSE );
  255.         EnableWindow( GetDlgItem( hDlg, IDC_FOREGROUND   ), FALSE );
  256.         EnableWindow( GetDlgItem( hDlg, IDC_BACKGROUND   ), FALSE );
  257.         EnableWindow( GetDlgItem( hDlg, IDC_IMMEDIATE    ), FALSE );
  258.         EnableWindow( GetDlgItem( hDlg, IDC_BUFFERED     ), FALSE );
  259.         EnableWindow( GetDlgItem( hDlg, IDC_WINDOWSKEY   ), FALSE );
  260.     }
  261.     else
  262.     {
  263.         SetDlgItemText( hDlg, IDC_CREATEDEVICE, TEXT("&Create Device") );
  264.         SetDlgItemText( hDlg, IDC_DATA, 
  265.                         TEXT("Device not created. Choose settings and click 'Create Device' then type to see results") );   
  266.  
  267.         EnableWindow( GetDlgItem( hDlg, IDC_EXCLUSIVE    ), TRUE );
  268.         EnableWindow( GetDlgItem( hDlg, IDC_NONEXCLUSIVE ), TRUE );
  269.         EnableWindow( GetDlgItem( hDlg, IDC_FOREGROUND   ), TRUE );
  270.         EnableWindow( GetDlgItem( hDlg, IDC_BACKGROUND   ), TRUE );
  271.         EnableWindow( GetDlgItem( hDlg, IDC_IMMEDIATE    ), TRUE );
  272.         EnableWindow( GetDlgItem( hDlg, IDC_BUFFERED     ), TRUE );
  273.  
  274.         if( !bExclusive && bForeground )
  275.             EnableWindow( GetDlgItem( hDlg, IDC_WINDOWSKEY ), TRUE );
  276.         else
  277.             EnableWindow( GetDlgItem( hDlg, IDC_WINDOWSKEY ), FALSE );
  278.     }
  279.  
  280.     // Figure what the user should expect based on the dialog choice
  281.     if( !bForeground && bExclusive )
  282.     {
  283.         _tcscpy( strExcepted, TEXT("For security reasons, background exclusive ") \
  284.                              TEXT("keyboard access is not allowed.\n\n") );
  285.     }
  286.     else
  287.     {
  288.         if( bForeground )
  289.         {
  290.             _tcscpy( strExcepted, TEXT("Foreground cooperative level means that the ") \
  291.                                  TEXT("application has access to data only when in the ") \
  292.                                  TEXT("foreground or, in other words, has the input focus. ") \
  293.                                  TEXT("If the application moves to the background, ") \
  294.                                  TEXT("the device is automatically unacquired, or made ") \
  295.                                  TEXT("unavailable.\n\n") );
  296.         }
  297.         else
  298.         {
  299.             _tcscpy( strExcepted, TEXT("Background cooperative level really means ") \
  300.                                  TEXT("foreground and background. A device with a ") \
  301.                                  TEXT("background cooperative level can be acquired ") \
  302.                                  TEXT("and used by an application at any time.\n\n") );
  303.         }
  304.  
  305.         if( bExclusive )
  306.         {
  307.             _tcscat( strExcepted, TEXT("Exclusive mode prevents other applications from ") \
  308.                                  TEXT("also acquiring the device exclusively. The fact ") \
  309.                                  TEXT("that your application is using a device at the ") \
  310.                                  TEXT("exclusive level does not mean that other ") \
  311.                                  TEXT("applications cannot get data from the device. ") \
  312.                                  TEXT("When an application has exclusive access to the ") \
  313.                                  TEXT("keyboard, DirectInput suppresses all keyboard ") \
  314.                                  TEXT("messages including the Windows key except ") \
  315.                                  TEXT("CTRL+ALT+DEL and ALT+TAB\n\n") );
  316.         }
  317.         else
  318.         {
  319.             _tcscat( strExcepted, TEXT("Nonexclusive mode means that other applications ") \
  320.                                  TEXT("can acquire device in exclusive or nonexclusive mode. ") );
  321.  
  322.             if( bDisableWindowsKey )
  323.             {
  324.                 _tcscat( strExcepted, TEXT("The Windows key will also be disabled so that ") \
  325.                                      TEXT("users cannot inadvertently break out of the ") \
  326.                                      TEXT("application. ") );
  327.             }
  328.  
  329.             _tcscat( strExcepted, TEXT("\n\n") );
  330.         }
  331.  
  332.         if( bImmediate )
  333.         {
  334.             _tcscat( strExcepted, TEXT("Immediate data is a snapshot of the current ") \
  335.                                  TEXT("state of a device. It provides no data about ") \
  336.                                  TEXT("what has happened with the device since the ") \
  337.                                  TEXT("last call, apart from implicit information that ") \
  338.                                  TEXT("you can derive by comparing the current state with ") \
  339.                                  TEXT("the last one. Events in between calls are lost.\n\n") );
  340.         }
  341.         else
  342.         {
  343.             _tcscat( strExcepted, TEXT("Buffered data is a record of events that are stored ") \
  344.                                  TEXT("until an application retrieves them. With buffered ") \
  345.                                  TEXT("data, events are stored until you are ready to deal ") \
  346.                                  TEXT("with them. If the buffer overflows, new data is lost.\n\n") );                             
  347.         }
  348.  
  349.         _tcscat( strExcepted, TEXT("The sample will read the keyboard 12 times a second. ") \
  350.                              TEXT("Typically an application would poll the keyboard ") \
  351.                              TEXT("much faster than this, but this slow rate is simply ") \
  352.                              TEXT("for the purposes of demonstration.") );
  353.     }
  354.  
  355.     // Tell the user what to expect
  356.     SetDlgItemText( hDlg, IDC_BEHAVIOR, strExcepted );
  357. }
  358.  
  359.  
  360.  
  361.  
  362. //-----------------------------------------------------------------------------
  363. // Name: OnCreateDevice()
  364. // Desc: Setups a the keyboard device using the flags from the dialog.
  365. //-----------------------------------------------------------------------------
  366. HRESULT OnCreateDevice( HWND hDlg )
  367. {
  368.     HRESULT hr;
  369.     BOOL    bExclusive;
  370.     BOOL    bForeground;
  371.     BOOL    bImmediate;
  372.     BOOL    bDisableWindowsKey;
  373.     DWORD   dwCoopFlags;
  374.  
  375.     // Cleanup any previous call first
  376.     KillTimer( hDlg, 0 );    
  377.     FreeDirectInput();
  378.  
  379.     // Detrimine where the buffer would like to be allocated 
  380.     bExclusive         = ( IsDlgButtonChecked( hDlg, IDC_EXCLUSIVE  ) == BST_CHECKED );
  381.     bForeground        = ( IsDlgButtonChecked( hDlg, IDC_FOREGROUND ) == BST_CHECKED );
  382.     bImmediate         = ( IsDlgButtonChecked( hDlg, IDC_IMMEDIATE  ) == BST_CHECKED );
  383.     bDisableWindowsKey = ( IsDlgButtonChecked( hDlg, IDC_WINDOWSKEY ) == BST_CHECKED );
  384.  
  385.     if( bExclusive )
  386.         dwCoopFlags = DISCL_EXCLUSIVE;
  387.     else
  388.         dwCoopFlags = DISCL_NONEXCLUSIVE;
  389.  
  390.     if( bForeground )
  391.         dwCoopFlags |= DISCL_FOREGROUND;
  392.     else
  393.         dwCoopFlags |= DISCL_BACKGROUND;
  394.  
  395.     // Disabling the windows key is only allowed only if we are in foreground nonexclusive
  396.     if( bDisableWindowsKey && !bExclusive && bForeground )
  397.         dwCoopFlags |= DISCL_NOWINKEY;
  398.  
  399.     // Create a DInput object
  400.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  401.                                          IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
  402.         return hr;
  403.     
  404.     // Obtain an interface to the system keyboard device.
  405.     if( FAILED( hr = g_pDI->CreateDevice( GUID_SysKeyboard, &g_pKeyboard, NULL ) ) )
  406.         return hr;
  407.     
  408.     // Set the data format to "keyboard format" - a predefined data format 
  409.     //
  410.     // A data format specifies which controls on a device we
  411.     // are interested in, and how they should be reported.
  412.     //
  413.     // This tells DirectInput that we will be passing an array
  414.     // of 256 bytes to IDirectInputDevice::GetDeviceState.
  415.     if( FAILED( hr = g_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
  416.         return hr;
  417.     
  418.     // Set the cooperativity level to let DirectInput know how
  419.     // this device should interact with the system and with other
  420.     // DirectInput applications.
  421.     hr = g_pKeyboard->SetCooperativeLevel( hDlg, dwCoopFlags );
  422.     if( hr == DIERR_UNSUPPORTED && !bForeground && bExclusive )
  423.     {
  424.         FreeDirectInput();
  425.         MessageBox( hDlg, _T("SetCooperativeLevel() returned DIERR_UNSUPPORTED.\n")
  426.                           _T("For security reasons, background exclusive keyboard\n")
  427.                           _T("access is not allowed."), _T("Keyboard"), MB_OK );
  428.         return S_OK;
  429.     }
  430.  
  431.     if( FAILED(hr) )
  432.         return hr;
  433.  
  434.     if( !bImmediate )
  435.     {
  436.         // IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
  437.         //
  438.         // DirectInput uses unbuffered I/O (buffer size = 0) by default.
  439.         // If you want to read buffered data, you need to set a nonzero
  440.         // buffer size.
  441.         //
  442.         // Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
  443.         //
  444.         // The buffer size is a DWORD property associated with the device.
  445.         DIPROPDWORD dipdw;
  446.  
  447.         dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  448.         dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  449.         dipdw.diph.dwObj        = 0;
  450.         dipdw.diph.dwHow        = DIPH_DEVICE;
  451.         dipdw.dwData            = SAMPLE_BUFFER_SIZE; // Arbitary buffer size
  452.  
  453.         if( FAILED( hr = g_pKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) )
  454.             return hr;
  455.     }
  456.  
  457.     // Acquire the newly created device
  458.     g_pKeyboard->Acquire();
  459.  
  460.     // Set a timer to go off 12 times a second, to read input
  461.     // Note: Typically an application would poll the keyboard
  462.     //       much faster than this, but this slow rate is simply 
  463.     //       for the purposes of demonstration
  464.     SetTimer( hDlg, 0, 1000 / 12, NULL );
  465.  
  466.     return S_OK;
  467. }
  468.  
  469.  
  470.  
  471.  
  472. //-----------------------------------------------------------------------------
  473. // Name: ReadImmediateData()
  474. // Desc: Read the input device's state when in immediate mode and display it.
  475. //-----------------------------------------------------------------------------
  476. HRESULT ReadImmediateData( HWND hDlg )
  477. {
  478.     HRESULT hr;
  479.     TCHAR   strNewText[256*5 + 1] = TEXT("");
  480.     TCHAR   strElement[10];    
  481.     BYTE    diks[256];   // DirectInput keyboard state buffer 
  482.     int     i;
  483.  
  484.     if( NULL == g_pKeyboard ) 
  485.         return S_OK;
  486.     
  487.     // Get the input's device state, and put the state in dims
  488.     ZeroMemory( diks, sizeof(diks) );
  489.     hr = g_pKeyboard->GetDeviceState( sizeof(diks), diks );
  490.     if( FAILED(hr) ) 
  491.     {
  492.         // DirectInput may be telling us that the input stream has been
  493.         // interrupted.  We aren't tracking any state between polls, so
  494.         // we don't have any special reset that needs to be done.
  495.         // We just re-acquire and try again.
  496.         
  497.         // If input is lost then acquire and keep trying 
  498.         hr = g_pKeyboard->Acquire();
  499.         while( hr == DIERR_INPUTLOST ) 
  500.             hr = g_pKeyboard->Acquire();
  501.  
  502.         // Update the dialog text 
  503.         if( hr == DIERR_OTHERAPPHASPRIO || hr == DIERR_NOTACQUIRED ) 
  504.             SetDlgItemText( hDlg, IDC_DATA, TEXT("Unacquired") );
  505.  
  506.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  507.         // may occur when the app is minimized or in the process of 
  508.         // switching, so just try again later 
  509.         return S_OK; 
  510.     }
  511.     
  512.     // Make a string of the index values of the keys that are down
  513.     for( i = 0; i < 256; i++ ) 
  514.     {
  515.         if( diks[i] & 0x80 ) 
  516.         {
  517.             wsprintf( strElement, TEXT("0x%02x "), i );
  518.             _tcscat( strNewText, strElement );
  519.         }
  520.     }
  521.  
  522.     // Get the old text in the text box
  523.     TCHAR strOldText[128];
  524.     GetDlgItemText( hDlg, IDC_DATA, strOldText, 127 );
  525.     
  526.     // If nothing changed then don't repaint - avoid flicker
  527.     if( 0 != lstrcmp( strOldText, strNewText ) ) 
  528.         SetDlgItemText( hDlg, IDC_DATA, strNewText );
  529.     
  530.     return S_OK;
  531. }
  532.  
  533.  
  534.  
  535.  
  536. //-----------------------------------------------------------------------------
  537. // Name: ReadBufferedData()
  538. // Desc: Read the input device's state when in buffered mode and display it.
  539. //-----------------------------------------------------------------------------
  540. HRESULT ReadBufferedData( HWND hDlg )
  541. {
  542.     TCHAR              strNewText[256*5 + 1] = TEXT("");
  543.     TCHAR              strLetter[10];    
  544.     DIDEVICEOBJECTDATA didod[ SAMPLE_BUFFER_SIZE ];  // Receives buffered data 
  545.     DWORD              dwElements;
  546.     DWORD              i;
  547.     HRESULT            hr;
  548.  
  549.     if( NULL == g_pKeyboard ) 
  550.         return S_OK;
  551.     
  552.     dwElements = SAMPLE_BUFFER_SIZE;
  553.     hr = g_pKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  554.                                      didod, &dwElements, 0 );
  555.     if( hr != DI_OK ) 
  556.     {
  557.         // We got an error or we got DI_BUFFEROVERFLOW.
  558.         //
  559.         // Either way, it means that continuous contact with the
  560.         // device has been lost, either due to an external
  561.         // interruption, or because the buffer overflowed
  562.         // and some events were lost.
  563.         //
  564.         // Consequently, if a button was pressed at the time
  565.         // the buffer overflowed or the connection was broken,
  566.         // the corresponding "up" message might have been lost.
  567.         //
  568.         // But since our simple sample doesn't actually have
  569.         // any state associated with button up or down events,
  570.         // there is no state to reset.  (In a real game, ignoring
  571.         // the buffer overflow would result in the game thinking
  572.         // a key was held down when in fact it isn't; it's just
  573.         // that the "up" event got lost because the buffer
  574.         // overflowed.)
  575.         //
  576.         // If we want to be cleverer, we could do a
  577.         // GetDeviceState() and compare the current state
  578.         // against the state we think the device is in,
  579.         // and process all the states that are currently
  580.         // different from our private state.
  581.         hr = g_pKeyboard->Acquire();
  582.         while( hr == DIERR_INPUTLOST ) 
  583.             hr = g_pKeyboard->Acquire();
  584.  
  585.         // Update the dialog text 
  586.         if( hr == DIERR_OTHERAPPHASPRIO || 
  587.             hr == DIERR_NOTACQUIRED ) 
  588.             SetDlgItemText( hDlg, IDC_DATA, TEXT("Unacquired") );
  589.  
  590.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  591.         // may occur when the app is minimized or in the process of 
  592.         // switching, so just try again later 
  593.         return S_OK; 
  594.     }
  595.  
  596.     // Study each of the buffer elements and process them.
  597.     //
  598.     // Since we really don't do anything, our "processing"
  599.     // consists merely of squirting the name into our
  600.     // local buffer.
  601.     for( i = 0; i < dwElements; i++ ) 
  602.     {
  603.         // this will display then scan code of the key
  604.         // plus a 'D' - meaning the key was pressed 
  605.         //   or a 'U' - meaning the key was released
  606.         wsprintf( strLetter, TEXT("0x%02x%s "), didod[ i ].dwOfs,
  607.                                          (didod[ i ].dwData & 0x80) ? TEXT("D") : TEXT("U"));
  608.         _tcscat( strNewText, strLetter );
  609.     }
  610.  
  611.     // Get the old text in the text box
  612.     TCHAR strOldText[128];
  613.     GetDlgItemText( hDlg, IDC_DATA, strOldText, 127 );
  614.  
  615.     // If nothing changed then don't repaint - avoid flicker
  616.     if( 0 != lstrcmp( strOldText, strNewText ) ) 
  617.         SetDlgItemText( hDlg, IDC_DATA, strNewText );    
  618.  
  619.     return S_OK;
  620. }
  621.  
  622.  
  623.  
  624.  
  625. //-----------------------------------------------------------------------------
  626. // Name: FreeDirectInput()
  627. // Desc: Initialize the DirectInput variables.
  628. //-----------------------------------------------------------------------------
  629. VOID FreeDirectInput()
  630. {
  631.     // Unacquire the device one last time just in case 
  632.     // the app tried to exit while the device is still acquired.
  633.     if( g_pKeyboard ) 
  634.         g_pKeyboard->Unacquire();
  635.     
  636.     // Release any DirectInput objects.
  637.     SAFE_RELEASE( g_pKeyboard );
  638.     SAFE_RELEASE( g_pDI );
  639. }
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.